#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>

void usage(const char *prog) {
    printf("用法: %s <起始物理地址> <结束物理地址> <输出文件>\n", prog);
    printf("例如: %s 0x3200c000 0x3200dfff out.txt\n", prog);
}

int main(int argc, char *argv[]) {
    if (argc != 4) {
        usage(argv[0]);
        return 1;
    }
    unsigned long start_addr = strtoul(argv[1], NULL, 0);
    unsigned long end_addr = strtoul(argv[2], NULL, 0);
    if (end_addr < start_addr) {
        fprintf(stderr, "结束地址必须大于等于起始地址\n");
        return 1;
    }
    size_t length = end_addr - start_addr + 1;
    size_t page_size = getpagesize();
    unsigned long page_base = start_addr & ~(page_size - 1);
    unsigned long page_offset = start_addr - page_base;
    size_t map_length = page_offset + length;

    int fd = open("/dev/mem", O_RDONLY | O_SYNC);
    if (fd < 0) {
        perror("打开 /dev/mem 失败");
        return 1;
    }
    void *map_base = mmap(NULL, map_length, PROT_READ, MAP_SHARED, fd, page_base);
    if (map_base == MAP_FAILED) {
        perror("mmap 失败");
        close(fd);
        return 1;
    }
    FILE *fout = fopen(argv[3], "w");
    if (!fout) {
        perror("输出文件打开失败");
        munmap(map_base, map_length);
        close(fd);
        return 1;
    }
    unsigned char *data = (unsigned char*)map_base + page_offset;
    size_t i = 0;
    for (; i + 16 <= length; i += 16) {
        fprintf(fout, "%08lx  ", start_addr + i);
        for (int j = 0; j < 4; ++j) {
            uint32_t val = *(uint32_t*)(data + i + j * 4);
            fprintf(fout, "%08x ", val);
        }
        fprintf(fout, "\n");
    }
    // 处理剩余不足16字节的部分
    if (i < length) {
        fprintf(fout, "%08lx  ", start_addr + i);
        int remain = (length - i) / 4;
        for (int j = 0; j < remain; ++j) {
            uint32_t val = *(uint32_t*)(data + i + j * 4);
            fprintf(fout, "%08x ", val);
        }
        // 补齐空位
        for (int j = remain; j < 4; ++j) {
            fprintf(fout, "         ");
        }
        fprintf(fout, "\n");
    }
    fclose(fout);
    munmap(map_base, map_length);
    close(fd);
    printf("读取完成，已保存 %zu 字节到 %s（文本格式）\n", length, argv[3]);
    return 0;
}